package com.charging.business.service;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.charging.business.config.MinFeeManager;
import com.charging.business.domain.FeeEntryInfoModel;
import com.charging.business.enums.Issuer;
import com.charging.business.enums.SpecialSituation;
import com.charging.business.enums.Vclass;
import com.charging.business.enums.Vsign;
import com.charging.business.exception.CustomizeException;
import com.charging.business.gantry.EntryFeeCalcResponse;
import com.charging.business.gantry.GantryCalcUtils;
import com.charging.business.qin.Db3FileUtils;
import com.charging.business.utils.BasicUtil;
import com.charging.business.utils.DateEx;
import com.charging.business.utils.RosterUtils;
import com.charging.business.utils.PayUtil;
import com.charging.business.vo.FeeExCalcRequest;
import com.charging.business.vo.FeeExCalcResponse;
import com.charging.business.vo.obj.EtcFeeInfo;
import com.charging.business.vo.obj.MiniFeeInfo;
import com.charging.business.vo.obj.SplitProvinceMini;
import com.charging.common.utils.DateUtils;
import com.charging.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @author JerryLu
 * @date 2024/9/27 11:11
 * @description 出口OBU计费
 */
@Component
public class FeeExEtcObuHandle {
    private static final Logger logger = LoggerFactory.getLogger(FeeExEtcObuHandle.class);

    //是否兜底标识
    public static boolean beWantMinFee = false;

    //是否转人工
    public static boolean beWantTurnMan = false;

    //用户卡车种
    public int ucVehicleClass = 0;

    //出口车种
    public int exVehicleClass = 0;

    public int exVehicleSign = 255;

    public String exVehicleId = "";

    public String ucVehicleId = "";

    //上次过门架时间
    public Long lastGantryTime = 0L;

    @Autowired
    private MinFeeManager minFeeManager;

    @Autowired
    private GantryCalcUtils gantryCalcUtils;

    @Autowired
    private RosterUtils rosterUtils;

    @Autowired
    private Db3FileUtils db3FileUtils;

    public FeeExCalcResponse run(FeeExCalcRequest request, FeeExCalcResponse response) throws CustomizeException {
        // 1、分析obu文件信息内容,解析到实体里
        request.parseTagFiles();
        // 2、对入出口时间、车牌、车型、轴数、车种、发行方等先批量处理
        this.init(request);
        // 3、兜底计费
        long s1 = System.currentTimeMillis();
        response = this.getMinFee(request, response);
        long s2 = System.currentTimeMillis();
        logger.info("最小费额算费结束,耗时{}毫秒", s2 - s1);

        // 4、标签卡内计费
        response = this.tagFee(request, response);
        long s3 = System.currentTimeMillis();
        logger.info("OBU卡内计费算费结束,耗时{}毫秒", s3 - s2);

        return response;
    }

    /**
     * 批量处理基本数据，设置异常特情
     *
     * @param request
     */
    public void init(FeeExCalcRequest request) throws CustomizeException {
        //用户卡车牌(含颜色),读取DF01下0015内容
        ucVehicleId = BasicUtil.formatVehicleId(request.card0015Model.getPlateNo(request.obuEf01Model.plateColor));
        String uc0019VehicleId = BasicUtil.formatVehicleId(request.card0019Model.getPlateNo(request.card0019Model.plateColor));
        //重置特情类型
        BasicUtil.resetSpecialInfo();
        //入出口车型对比
//        if (!request.getEnVehicleType().equals(request.getExVehicleType())) {
//            BasicUtil.setSpecialInfo(SpecialSituation.TYPE51.getValue());
//            logger.warn(SpecialSituation.TYPE51.getDescription());
//        }
        //入出口车牌对比
        exVehicleId = BasicUtil.formatVehicleId(request.getVehicleId());
        if (!BasicUtil.compareVehicleId(exVehicleId, ucVehicleId, true) || !BasicUtil.compareVehicleId(exVehicleId, uc0019VehicleId, true)) {
            BasicUtil.setSpecialInfo(SpecialSituation.TYPE52.getValue());
            logger.warn(SpecialSituation.TYPE52.getDescription());
        } else if (!BasicUtil.compareVehicleId(ucVehicleId, uc0019VehicleId, true)) {
            BasicUtil.setSpecialInfo(SpecialSituation.TYPE41.getValue());
            logger.warn(SpecialSituation.TYPE41.getDescription());
        }
        //入出口轴数对比
//        if (request.getEnAxleCount() != request.getExAxleCount()) {
//            BasicUtil.setSpecialInfo(SpecialSituation.TYPE60.getValue());
//            logger.warn(SpecialSituation.TYPE60.getDescription());
//        }
        //U型车检查
        if (Objects.equals(request.getEnStationHex(), request.getExStationHex())) {
            BasicUtil.setSpecialInfo(SpecialSituation.TYPE111.getValue());
            logger.warn(SpecialSituation.TYPE111.getDescription());
        }

        //入出口车种处理
        ucVehicleClass = Vclass.getEtcVCLASS(request.getEnVehicleType(), request.card0015Model.vehicleUserType, request.obuEf01Model.vehicleUserType, ucVehicleId);
        exVehicleClass = Vclass.getEtcVCLASS(request.getExVehicleType(), request.vehicleUserType, -1, exVehicleId);
        List<Integer> values = Arrays.asList(Vclass.MTC_GREEN, Vclass.MTC_COMHV, Vclass.MTC_LARGE);
        if (values.contains(exVehicleClass)) {
            // 出口为绿通、联合收割、大件运输
            if (exVehicleClass == Vclass.MTC_GREEN) {
                exVehicleSign = Vsign.GREEN;
            } else if (exVehicleClass == Vclass.MTC_COMHV) {
                exVehicleSign = Vsign.COMHV;
            } else if (exVehicleClass == Vclass.MTC_LARGE) {
                exVehicleSign = Vsign.ETCLARGE;
            }

            if (BasicUtil.compareVehicleId(exVehicleId, ucVehicleId, false)) {
                exVehicleClass = ucVehicleClass;
            }
        }

        lastGantryTime = request.obuEf04Model.lastGantryTime();
        logger.info("OBU信息：车牌号：{}，车型：{}，用户类型：{}，过省数量：{}", ucVehicleId, request.obuEf01Model.vehicleType, request.obuEf01Model.vehicleUserType, request.obuEf04Model.provCount);

        logger.info("卡基本信息：卡内部编号：{}，卡片网络编号：{}，发行方：{}，车牌号：[{}]-[{}]，用户类型：{}，车型：{}，状态标识：{}",
                request.card0015Model.cardNo, request.card0015Model.cardWork, request.card0015Model.issueSign, ucVehicleId, uc0019VehicleId,
                request.card0015Model.vehicleUserType, request.card0019Model.vehicleType, request.card0019Model.vehicleSign);

        logger.info("请求参数信息：入出口站：[{}]-[{}]，入出口时间：[{}]-[{}]，入出口车牌：[{}]-[{}]-[{}]，入出口车型：[{}]-[{}]，入出口轴数：[{}]-[{}]，入出口车种：[{}]-[{}]，用户类型：{}，状态标识：{}，passId：{}",
                request.getEnStationId(), request.getExStationId(), DateUtils.convertTime(request.getEnTime()), DateUtils.convertTime(request.getExTime()), ucVehicleId, uc0019VehicleId,
                exVehicleId, request.getEnVehicleType(), request.getExVehicleType(), request.getEnAxleCount(),
                request.getExAxleCount(), ucVehicleClass, exVehicleClass, request.getVehicleUserType(), request.getVehicleSign(), request.getPassId());
    }

    /**
     * 兜底计费，分省合并
     *
     * @param request
     * @param response
     * @return
     * @throws CustomizeException
     */
    public FeeExCalcResponse getMinFee(FeeExCalcRequest request, FeeExCalcResponse response) throws CustomizeException {
        // 获取最小费额版本号
        boolean bETC = true;
        try {
            MiniFeeInfo miniFeeInfo = new MiniFeeInfo();
            String minVersion = minFeeManager.getCurrentVersion();
            miniFeeInfo.spcRateVersion = minVersion;
            ArrayList<SplitProvinceMini> minProvinces = new ArrayList<>();
            if (request.getExStationHex().startsWith(Issuer.Issue610101.getProvinceCode())) {
                //陕西
                try {
                    db3FileUtils.loadDb3File(request.getEnStationId(), request.getExStationId(), request.getExVehicleType());
                    minProvinces = minFeeManager.getMinFee(bETC, request.getEnStationId(), request.getExStationId(), request.getExVehicleType());
                } catch (Exception e) {
                    throw new CustomizeException("获取最小费额失败");
                }
            } else {
                minProvinces = rosterUtils.getMiniFee(request.getEnStationId(), request.getExStationId(), request.getExVehicleType(), request.getExAxleCount(), bETC);
            }
            if (minProvinces.isEmpty()) {
                throw new CustomizeException("获取兜底计费失败：查询不到对应的出口计费信息");
            }

            // 汇总最小费额信息
            for (SplitProvinceMini prov : minProvinces) {
                miniFeeInfo.zMinPayFee += prov.ziMinPayFee;
                miniFeeInfo.zMinFee += prov.ziMinFee;
                miniFeeInfo.calMinFeeFee += prov.calMinFeeFee;
                miniFeeInfo.calMinFeeFee95 += prov.calMinFeeFee95;
                miniFeeInfo.calMinFeeMileage += prov.calMinFeeMileage;
            }
            miniFeeInfo.splitProvince = minProvinces;
            //陕西合并分省信息
            if (request.getExStationHex().startsWith(Issuer.Issue610101.getProvinceCode())) {
                miniFeeInfo.merge();
            }

            response.setSpcRateVersion(minVersion);
            response.setMiniFeeInfo(miniFeeInfo);
            response.setExitFeeType(6);
            logger.info("最小费额结果：通行省份个数：{}，总应收：{}元，总实收：{}元，95折总实收：{}元，总里程：{}公里，费额费率版本号：{}", miniFeeInfo.splitProvince.size(), PayUtil.convertFee(miniFeeInfo.calMinFeeFee), PayUtil.convertFee(miniFeeInfo.zMinFee), PayUtil.convertFee(miniFeeInfo.calMinFeeFee95), PayUtil.convertMileage(miniFeeInfo.calMinFeeMileage), minVersion);
        } catch (CustomizeException e) {
            throw new CustomizeException(!e.getMessage().isEmpty() ? e.getMessage() : "获取兜底计费异常");
        }
        return response;
    }

    /**
     * 动态库计费
     *
     * @param request
     * @param response
     * @return
     * @throws CustomizeException
     */
    public FeeExCalcResponse tagFee(FeeExCalcRequest request, FeeExCalcResponse response) throws CustomizeException {
        //调取动态库获取计费信息
        EtcFeeInfo etcFeeInfo = new EtcFeeInfo();
        FeeEntryInfoModel etcDto = JSONObject.parseObject(JSON.toJSONString(request), FeeEntryInfoModel.class);
        etcDto.setTagType(1);
        etcDto.setLaneStatus(4);
        etcDto.setEnPassTime(request.getEnTime());
        etcDto.setLastGantryFee(0);
        etcDto.setLastFeeMileage(0);
        etcDto.setCardNetwork(request.obuEf04Model.getCardWork());
        etcDto.setVehicleUserType(request.getVehicleUserType());
        etcDto.setAxleCount(0);
        etcDto.setVehicleType(request.getExVehicleType());
        etcDto.setCardType(request.getCPUCardType());
        etcDto.setCardVer(request.getCPUVersion());
        etcDto.setPlateHex(request.getVehicleId().split("_")[0]);
        etcDto.setPlateColor(Integer.valueOf(request.getVehicleId().split("_")[1]));
        etcDto.setFeeSumLocal(request.getPreBalance().intValue());
        if (request.getExVehicleType() < 10) {
            etcDto.setVehicleWeightLimits(request.obuEf01Model.vehicleSeat);
        } else {
            etcDto.setVehicleWeightLimits(request.obuEf01Model.approvedLoad);
        }
        etcDto.setTotalWeight(request.obuEf04Model.enWeight());
        etcDto.setFeeProvGantryNum(request.obuEf04Model.provSumCount);
        etcDto.setEnAxleCount(request.getEnAxleCount());
        etcDto.setVehicleClass(request.getVehicleClass());
        etcDto.setIssuerId(request.getIssuerId());
        if (StringUtils.isNotEmpty(request.getVehicleSign())) {
            String hex = request.getVehicleSign();
            if (hex.startsWith("0x") || hex.startsWith("0X")) {
                hex = hex.substring(2);
            }
            etcDto.setVehicleStatusFlag(Integer.parseInt(hex, 16));
        } else {
            etcDto.setVehicleStatusFlag(0xFF);
        }
        etcDto.setEnTollStationHex(request.getEnStationHex());
        etcDto.setLastGantryHex(request.obuEf04Model.lastGantryHex());
        etcDto.setLastPassTime(LocalDateTime.parse(DateEx.ut2str(lastGantryTime.intValue(), "yyyy-MM-dd'T'HH:mm:ss")));
        etcDto.setCurPassTime(DateUtils.convertTimestampT(lastGantryTime.intValue()));
        etcDto.setFeeProvBeginHex(request.obuEf04Model.provEntryHex);
        etcDto.setFeeProvMileage(request.obuEf04Model.sumMileage);
        etcDto.setPayFeeSumLocal(request.obuEf04Model.provSumPayFee);
        etcDto.setRealFeeSumLocal(request.obuEf04Model.provSumFee);
        etcDto.setGantryPassNum(0);
        etcDto.setGantryPassHex("");
        EntryFeeCalcResponse responseDto = gantryCalcUtils.libraryFee(etcDto);
        if (responseDto.getCode() != 0) {
            response.setCode(-1);
            response.setCodeInfo(responseDto.getMsg());
            response.setMiniFeeInfo(null);
            response.setRateVersion(null);
            response.setSpcRateVersion(null);
            throw new CustomizeException(responseDto.getMsg());
        } else {
            response.setRateVersion(responseDto.getParamVersion());
            // 多省判断
//            if (request.obuEf04Model.provCount > 1 || !request.obuEf04Model.tstLocalEntry()) {
//                etcFeeInfo.zMultiProvinces = true;
//                etcFeeInfo.zProvinceCount = request.obuEf04Model.provCount;
//            } else {
//                etcFeeInfo.zMultiProvinces = false;
//                etcFeeInfo.zProvinceCount = 1;
//            }

            // 前序行程应收金额
            int otherProvSumPayFee = request.obuEf04Model.sumPayFee - request.obuEf04Model.provSumPayFee;
            // 前序行程实收金额
            int otherProvSumFee = request.obuEf04Model.sumFee - request.obuEf04Model.provSumFee;
//            if (request.obuEf04Model.provCount > 1) {// 前序行程非本省行程，涉及跨省 todo
//                otherProvSumPayFee = request.obuEf04Model.sumPayFee;   //全程累计应收均为前序行程的
//                otherProvSumFee = request.obuEf04Model.sumFee;     //全程累计实收均为前序行程的
//            }

            otherProvSumPayFee = Math.max(otherProvSumPayFee, 0);
            otherProvSumFee = Math.max(otherProvSumFee, 0);
            //总应收, 前序行程+最后行程
            etcFeeInfo.payFee = otherProvSumPayFee + responseDto.getFeeSpare1();
            //总实收, 前序行程+最后行程
            etcFeeInfo.fee = otherProvSumFee + responseDto.getFeeProvSumLocal();
            //总里程, 已有+拟合
            etcFeeInfo.feeMileage = request.obuEf04Model.sumMileage + responseDto.getFeeMileage();
            //总优惠
            etcFeeInfo.discountFee = etcFeeInfo.payFee - etcFeeInfo.fee;
            //总优惠校验
            if (etcFeeInfo.discountFee < 0) {
                etcFeeInfo.payFee = etcFeeInfo.fee;
                etcFeeInfo.discountFee = 0;
            }
            //设置计费信息
            etcFeeInfo.setInfo(responseDto);
            logger.info("OBU设备内计费结果：通行省份个数：{}，总应收：{}元，总优惠：{}元，总实收：{}元，总里程：{}公里", request.obuEf04Model.provCount, PayUtil.convertFee(etcFeeInfo.payFee), PayUtil.convertFee(etcFeeInfo.discountFee), PayUtil.convertFee(etcFeeInfo.fee), PayUtil.convertMileage(etcFeeInfo.feeMileage));

            //计费验证
            int spFee = etcFeeInfo.payFee;
//            if (spFee == 0) {
//                spFee = 1;
//            }
            // 获取ETC兜底收费金额
            // 不需要对本省免费进行特殊处理
            // 不需要对本省免费进行强制免费处理
            int minFee = response.miniFeeInfo.calMinFeeFee;
//            if (minFee == 0) {
//                minFee = 1;
//            }
            //设备内总里程
            int spMileage = etcFeeInfo.feeMileage;
            //最小费额里程
            int minMileage = response.miniFeeInfo.calMinFeeMileage;
            /**
             * 1.最小费额应收下限值：最小费额应收金额-（通行省份数量*0.5元）
             * 2.最小费额应收上限值：最小费额应收金额*1.5
             * 3.最小费额应收里程上限值：最小费额应收里程*1.5
             * 4.设备内应收金额大于等于最小费额应收下限值且设备内应收金额小于等于最小费额应收上限值时使用设备内金额计费
             * 5.设备内应收金额大于最小费额应收上限值且设备内里程小于最小费额应收里程上限值时使用设备内金额计费
             * 7.大件运输车或者大于6轴车辆拦截转人工
             * 8.其他情况拦截转人工
             */
            if (request.getValidShortFee() == null || request.getValidShortFee() == 1) {
                if (request.getExStationHex().startsWith(Issuer.Issue140101.getProvinceCode())) {
                    if (request.getExAxleCount() <= 6) {
                        int proCount = request.obuEf04Model.provCount;
                        if (spFee >= (minFee - (proCount * 50f)) && spFee <= minFee * 1.5f) {
                            beWantMinFee = false;
                        } else if (spFee > minFee * 1.5f && spMileage < minMileage * 1.5f) {
                            beWantMinFee = false;
                        } else {
                            logger.info("小于6轴其他情况拦截转人工,走兜底");
                            //转人工
                            beWantTurnMan = true;
                            // 转兜底
                            beWantMinFee = true;
                        }
                    } else if (request.getVehicleUserType() == 25 || request.getVehicleClass() == 25) {
                        logger.info("大件运输车拦截转人工,正常返回计费");
                        //转人工
                        beWantTurnMan = true;
                        BasicUtil.setSpecialInfo(SpecialSituation.TYPE134.getValue());
                    } else {
                        logger.info("其他情况拦截转人工，走兜底");
                        //转人工
                        beWantTurnMan = true;
                        BasicUtil.setSpecialInfo(SpecialSituation.TYPE135.getValue());
                        // 转兜底
                        beWantMinFee = true;
                    }
                } else {
                    //包年车辆：15-绕城包年 16-西阎包年 17-绕城西阎包年
                    int vehicleUserType = request.getVehicleUserType();
                    int basicAmount = 0;
                    double amount = 0;
                    double lowAmount;
                    double upperAmount;
                    if (vehicleUserType == 15) {
                        basicAmount = 4371;
                        amount = minFee * 0.9f - basicAmount;
                        lowAmount = amount < 0 ? 0 : amount;
                    } else if (vehicleUserType == 16) {
                        basicAmount = 2825;
                        amount = minFee * 0.9f - basicAmount;
                        lowAmount = amount < 0 ? 0 : amount;
                    } else if (vehicleUserType == 17) {
                        basicAmount = 7196;
                        amount = minFee * 0.9f - basicAmount;
                        lowAmount = amount < 0 ? 0 : amount;
                    } else {
                        lowAmount = minFee * 0.9f;
                    }

                    if (request.getExVehicleType() == 1) {
                        upperAmount = minFee * 15f;
                    } else {
                        upperAmount = minFee * 5f;
                    }
                    beWantMinFee = !(spFee >= lowAmount) || !(spFee <= upperAmount);
                }
            }
            if (!beWantMinFee) {
                response.setEtcFeeInfo(etcFeeInfo);
                response.setExitFeeType(1);
            }
        }
        return response;
    }
}
